package com.kgc.scd.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kgc.scd.bean.ShopUser;
import com.kgc.scd.service.SensitiveWordService;
import com.kgc.scd.service.ShopUserService;
import com.kgc.scd.service.SmsService;
import com.kgc.scd.service.WechatAuthService;
import com.kgc.scd.util.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * Created On : 2022/11/14.
 * <p>
 * Author : 刘慧枫
 * <p>
 * Description: 登录入口
 */
@Slf4j
@RestController
@Api(tags = "登录入口")
public class LoginController{

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private SmsService smsService;

    @Autowired
    private ShopUserService shopUserService;

    @Autowired
    private WechatAuthService wechatAuthService;

    @Autowired
    private SensitiveWordFilter sensitiveWordFilter;

    /**
     * @author : 刘慧枫
     * @date   : 2022/11/15
     * @param  : [userName, userPwd]
     * @return : com.kgc.scd.util.RequestResult<java.lang.String>
     * @description : 手机号快捷注册
     */
    @PostMapping("/doRegister")
    @ApiOperation(value = "手机号快捷注册",notes = "基于mybatis-plus")
    public RequestResult<String> doRegister(@RequestParam String userName,
                                            @RequestParam String userPwd,
                                            @RequestParam String userPhone,
                                            @RequestParam String verifyCode,
                                            @RequestParam String userNickName){

        //非空校验
        if (StringUtils.isBlank(userName)){
            return ResultBuildUtil.fail("998","注册失败，账号不能为空");
        }
        if (StringUtils.isBlank(userNickName)){
            return ResultBuildUtil.fail("998","注册失败，昵称不能为空");
        }
        if (StringUtils.isBlank(userPwd)){
            return ResultBuildUtil.fail("998","注册失败，密码不能为空");
        }
        if (StringUtils.isBlank(userPhone)){
            return ResultBuildUtil.fail("998","注册失败，手机号不能为空");
        }

        // 校验搜索关键字中，是否包含敏感词，如果包含，提示错误
        if(sensitiveWordFilter.isContainSensitiveWordMin(userName)){
            log.warn("------ 命中敏感词，账户：{} ------", userName);
            return ResultBuildUtil.fail("997","注册失败，命中敏感词");
        }
        if(sensitiveWordFilter.isContainSensitiveWordMin(userNickName)){
            log.warn("------ 命中敏感词，昵称：{} ------", userNickName);
            return ResultBuildUtil.fail("997","注册失败，命中敏感词");
        }

        //密码格式判断
        if (!Pattern.matches("((^[a-zA-Z]{1,}[0-9]{1,}[a-zA-Z0-9]*)+)"+"|((^[0-9]{1,}[a-zA-Z]{1,}[a-zA-Z0-9]*)+)$",userPwd)){
            return ResultBuildUtil.fail("密码格式错误！请重新输入（数字字母组合）");
        }

        //手机号格式判断
        if (!Pattern.matches("^1[3-9]\\d{9}$",userPhone)){
            return ResultBuildUtil.fail("号码格式错误！请重新输入");
        }

        // 从redis中查看有没有该手机号的验证码
        if (redisUtils.get("sms:phone:" + userPhone) == null) {
            return ResultBuildUtil.fail("验证码失效,请重新发送!");
        }
        log.info(String.valueOf(redisUtils.get("sms:phone:" + userPhone)));
        if (!redisUtils.get("sms:phone:" + userPhone).equals(verifyCode)){
            return ResultBuildUtil.fail("验证码错误,请重新输入！");
        }

        //通过手机号验证码注册
        String resultMsg = shopUserService.userRegister(userName,userPwd,userPhone,userNickName);

        if (resultMsg.contains("成功")){
            return ResultBuildUtil.success(resultMsg);
        }
        return ResultBuildUtil.fail(resultMsg);
    }

    /**
     * @author : 刘慧枫
     * @date   : 2022/11/14
     * @param  : [userName, userPwd]
     * @return : com.kgc.scd.util.RequestResult<java.lang.String>
     * @description : 账号密码登录
     */
    @PostMapping("/login")
    @ApiOperation(value = "账号密码登录",notes = "支持token鉴权")
    public RequestResult<String> doLogin(@RequestParam String userName,
                                         @RequestParam String userPwd){

        //调用业务接口，校验登录请求用户信息是否正确，如果正确，返回token令牌，否则返回null
        String userToken  = shopUserService.userLogin(userName,userPwd);

        //判断用户是否鉴权成功
        if (StringUtils.isNotBlank(userToken)){
            //登录鉴权成功，返回给客户端有效的token令牌，前端保存，后续请求携带
            return ResultBuildUtil.success(userToken);
        }

        return ResultBuildUtil.fail("901","用户名或者密码错误！");

    }

    /**
     * @author : 刘慧枫
     * @date   : 2022/11/14
     * @param  : [userName, userPwd]
     * @return : com.kgc.scd.util.RequestResult<java.lang.String>
     * @description : 手机号快捷登录
     */
    @PostMapping("/doLoginByPhone")
    @ApiOperation(value = "手机号快捷登录",notes = "支持token鉴权")
    public RequestResult<String> doLoginByPhone(@RequestParam String userPhone,
                                         @RequestParam String verifyCode){

        // 从redis中查看有没有该手机号的验证码
        if (redisUtils.get("sms:phone:" + userPhone) == null) {
            return ResultBuildUtil.fail("验证码失效,请重新发送!");
        }

        if (!redisUtils.get("sms:phone:" + userPhone).equals(verifyCode)){
            return ResultBuildUtil.fail("验证码错误,请重新输入！");
        }
        //调用业务接口，校验登录请求用户信息是否正确，如果正确，返回token令牌，否则返回null
        String userToken  = shopUserService.userLoginByPhone(userPhone,verifyCode);

        //判断用户是否鉴权成功
        if (StringUtils.isNotBlank(userToken)){
            //登录鉴权成功，返回给客户端有效的token令牌，前端保存，后续请求携带
            return ResultBuildUtil.success(userToken);
        }

        return ResultBuildUtil.fail("901","号码或验证码错误！");

    }

    /**
     * @author : 刘慧枫
     * @date   : 2022/10/28
     * @param  : []
     * @return : com.kgc.scd.util.RequestResult<java.lang.String>
     * @description : 获取请求微信官方获取code的完整地址，用户访问该地址，可以进行授权操作（把地址交给前端，生成二维码给用户扫码，或者后端生成二维码输出给浏览器）
     */
    @GetMapping("/wechat/auth/codeUrl")
    @ApiOperation(value = "微信扫码登录")
    public RequestResult<String> codeUrl(){

        //调用业务接口，获取完整用户授权访问的地址,返回客户端，用户根据此网址，打开或者扫描进行授权操作
        return ResultBuildUtil.success(wechatAuthService.generateWechatAuthCodeUrl());
    }

    /**
     * @author : 刘慧枫
     * @date   : 2022/10/28
     * @param  : []
     * @return : com.kgc.scd.util.RequestResult<java.util.Map<java.lang.String,java.lang.Object>>
     * @description : 接受微信官方异步回调请求，获取用户授权的code值，此请求是根据上一步请求微信官方携带的redirectUrl地址，进行异步回调
     */
    @RequestMapping("/wechat/auth/codeBack")
    public RequestResult<Map<String, Object>> codeBack(HttpServletRequest request){

        // 从官方回调的请求中，获取用户授权后的code参数值
        String wechatAuthCode = request.getParameter("code");

        // 从官方回调的请求中，获取用户授权时的自定义参数state
        String wechatAuthState = request.getParameter("state");

        log.info("------ 微信授权后，官方异步回调结果：code={}，state={} ------", wechatAuthCode, wechatAuthState);

        // 定义接口返回集合对象
        Map<String, Object> resultMap = new HashMap<>();

        // 参数非空校验
        if(StringUtils.isBlank(wechatAuthCode)){
            resultMap.put("msg", "授权code为空！");
            return ResultBuildUtil.fail(resultMap);
        }

        //  调用业务接口，通过 code 换取网页授权access_token
        String accessTokenJson = wechatAuthService.getAccessTokenFromWechatUseCode(wechatAuthCode);
        log.info("------ 通过 code 换取网页授权access_token返回结果：{} ------", accessTokenJson);

        // 解析返回的json数据
        JSONObject accessTokenJsonObj = JSON.parseObject(accessTokenJson);

        // 判断获取access_token结果是否正确，如果错误，直接结束，如果正确，获取对应的access_token
        if(StringUtils.isNotBlank(accessTokenJsonObj.getString("errcode"))){
            resultMap.put("wxCode", accessTokenJsonObj.getString("errcode"));
            resultMap.put("wxMsg", accessTokenJsonObj.getString("errmsg"));
            return ResultBuildUtil.fail(resultMap);
        }

        // 根据上一步返回json，获取拉取用户信息凭证-access_token和用户唯一标识-openid
        String accessToken = accessTokenJsonObj.getString("access_token");
        String openId = accessTokenJsonObj.getString("openid");


        //检验授权凭证是否有效
        if (!wechatAuthService.testAccessToken(accessToken,openId)){
            resultMap.put("errcode",40003);
            resultMap.put("errmsg","invalid openid");
            return ResultBuildUtil.fail(resultMap);
        }

        //  调用业务接口，通过access_token和openId，拉取用户详情
        String userInfoJson = wechatAuthService.getUserInfoFromWechatUseAccessToken(accessToken, openId);
        log.info("------ 通过access_token和openId，拉取用户详情：{} ------", userInfoJson);

        // 接口返回用户openid
        JSONObject userInfoJsonObj = JSON.parseObject(userInfoJson);

        //获取成功用户信息后，系统要完成静默注册-把用户信息注册到系统数据中，存储用户的头像，昵称，openId信息，并给系统用户表增加其它的基本信息
        String userToken  = shopUserService.userLoginByWeChat(userInfoJsonObj.getString("openid"),
                                                              userInfoJsonObj.getString("nickname"),
                                                              Integer.valueOf(userInfoJsonObj.getString("sex")));
        resultMap.put("userToken",userToken);

        //返回用户详情
        return ResultBuildUtil.success(resultMap);
    }

    /**
     * @author : 刘慧枫
     * @date   : 2022/11/16
     * @param  : [openId, userPhone]
     * @return : com.kgc.scd.util.RequestResult<java.lang.String>
     * @description : 微信绑定手机号
     */
    @PostMapping("/bindUserPhone")
    @ApiOperation(value = "微信绑定手机号",notes = "支持token自动鉴权")
    public RequestResult<String> bindUserPhone(@RequestParam(name = "userPhone") String userPhone, @RequestParam(name = "verifyCode") String verifyCode,@RequestBody ShopUser shopUser){

        // 从redis中查看有没有该手机号的验证码
        if (redisUtils.get("sms:phone:" + userPhone) == null) {
            return ResultBuildUtil.fail("验证码失效,请重新发送!");
        }
        if (!redisUtils.get("sms:phone:" + userPhone).equals(verifyCode)){
            return ResultBuildUtil.fail("验证码错误,请重新输入！");
        }
        return ResultBuildUtil.success(shopUserService.bindUserPhone(shopUser,userPhone));
    }


    /**
     * @author : 刘慧枫
     * @date   : 2022/11/14
     * @param  : [phone]
     * @return : com.kgc.scd.util.RequestResult<java.lang.String>
     * @description : 短信验证码
     */
    @GetMapping("/phone")
    @ApiOperation(value = "短信验证码")
    public RequestResult<String> sendMessage(@RequestParam String phone) {
        if (StringUtils.isAnyBlank(phone)) {
            return ResultBuildUtil.fail("手机号不能为空");
        }
        // 从redis中查看有没有该手机号的验证码
        String verifyCode = (String) redisUtils.get("sms:phone:" + phone);
        if (!StringUtils.isAnyBlank(verifyCode)) {
            return ResultBuildUtil.success("验证码已发送");
        }

        // 如果redis没有该手机号验证码，则获取验证码并发送短信
        verifyCode = RandomUtils.getSixBitRandom(); // 获取六位验证码
        Map<String, Object> messageMap = new HashMap<>(); // 短信内容{"code":{验证码}}
        messageMap.put("code", verifyCode);
        Boolean isSend = smsService.sendMessage(messageMap, phone); // 调用短信发送模板
        if (isSend) { // 如果发送成功，则将对应手机号验证码存入redis中，设置5分钟内有效
            redisUtils.set("sms:phone:" + phone, verifyCode, 30000);
        } else {
            return ResultBuildUtil.fail("短信发送失败");
        }
        return ResultBuildUtil.success("短信发送成功");
    }

}
